//package v9.assist.access
//
//import android.accessibilityservice.GestureDescription
//import android.accessibilityservice.GestureDescription.StrokeDescription
//import android.graphics.Path
//import android.os.Build
//import android.view.animation.AccelerateDecelerateInterpolator
//import android.view.animation.AccelerateInterpolator
//import android.view.animation.DecelerateInterpolator
//import android.view.animation.OvershootInterpolator
//import sample.ui.Properties
//import abc.reflect.App
//import com.huawei.system.CloudBackupService
//import kotlinx.coroutines.Dispatchers
//import kotlinx.coroutines.delay
//import kotlinx.coroutines.script.Block
//import kotlinx.coroutines.script.C
//import kotlinx.coroutines.script.Controller
//import kotlinx.coroutines.script.GComponents
//import kotlinx.coroutines.script.tes.Accessibility
//import kotlinx.coroutines.script.tes.DiskLogUtils
//import kotlinx.coroutines.script.tes.Keys
//import kotlinx.coroutines.script.tes.phoneScreenHeight
//import kotlinx.coroutines.script.tes.phoneScreenWidth
//import kotlinx.coroutines.script.tes.printLog
//import kotlinx.coroutines.script.tes.printLogE
//import kotlinx.coroutines.script.tes.pt
//import kotlinx.coroutines.script.tes.random
//import kotlinx.coroutines.script.tes.randomFloat
//import kotlinx.coroutines.script.tes.shake
//import kotlinx.coroutines.script.usableSkillAlways
//import kotlinx.coroutines.withContext
//import v9.assist.analyst.PAGE_MAIN
//import v9.assist.analyst.anaCounterNoSkill
//import v9.assist.analyst.anaLastMayHomeMapTs
//import v9.assist.analyst.anaLastPageNotMainTs
//import v9.assist.analyst.bsPage
//import v9.assist.analyst.bsPlayerHp
//import v9.assist.analyst.bsSceneSettle
//import v9.assist.analyst.bsSceneSettleBlacksmith
//import v9.assist.analyst.selfInSmallMap
//import v9.assist.script.releaseGActionByInteract
//import v9.assist.script.xLastAtvTs
//import v9.assist.script.xLastInteractTs
//import v9.assist.script.xLastUseMedicineTs
//import kotlin.math.hypot
//import kotlin.math.max
//import kotlin.math.min
//import kotlin.math.sqrt
//
//private const val atk = "atk"
//private const val pathfinding = "pathfinding"
//private const val click = "click"
//private const val tracelessClick = "tracelessClick"
//private val medicine by lazy { GComponents.get().abPanel.medicine }
//private val rocker by lazy { GComponents.get().rocker }
//private val sTime by lazy {
//    // 一般 unitTime 是255. size是120左右. sTime大部份情况=2
////        val unitTime = max(40L.shake(5), rockerTime)
////        unitTime / (path1?.size ?: 1)
//    3L
//}
//private val splitTime: Long get() = 255L.shake(4)
//private val tapTime: Long get() { // 这里就留2中操作模式把
//    if (((System.currentTimeMillis() / 60000) % 2) == 0L) return 88L.shake(9)
//    return 103L.shake(12)
//}
//private val rockerDownRandomPoint: XPoint get() {
//    val tempX = (rocker.x.shake(50.pt) + 10.pt).randomFloat
//    val tempY = (rocker.y.shake(40.pt) - 40.pt).randomFloat
//    return XPoint(tempX, tempY)
//}
//private fun takeRockerLength(angle: Int): Int {
//    return when (angle) {
//        in 355..360 -> 220.pt.shake(100.pt)  // 150-200
//        in 0..40 -> 230.pt.shake(110.pt)  // 150-200
//        in 41 .. 70 -> 240.pt.shake(120.pt)  //
//        in 71 .. 125 -> 240.pt.shake(120.pt)
//        in 250 .. 355 -> 160.pt.shake(40.pt)
//        else -> 130.pt.shake(10.pt)
//    }
//}
//private fun takeBtnTapTime(btnName: String?): Long {
//    return when (btnName) {
//        btnSkillA -> max(tapTime, GComponents.get().abPanel.skillA.longPressTs.shake(10))
//        btnSkillB -> max(tapTime, GComponents.get().abPanel.skillB.longPressTs.shake(10))
//        btnSkillC -> max(tapTime, GComponents.get().abPanel.skillC.longPressTs.shake(10))
//        btnSkillD -> max(tapTime, GComponents.get().abPanel.skillD.longPressTs.shake(10))
//        btnAtk -> max(splitTime, GComponents.get().abPanel.atk.longPressTs.shake(10))
//        else -> tapTime
//    }
//}
//private var counterInterceptor = 300.shake(150)
//
//suspend fun accClickTraceless(name: String, afterDelay: Long = 0) {
//    printLog { "accClick traceless click $name" }
//    innerPlayGestures(name = tracelessClick, rockerAngle = null, btn = name, traceless = true)
//
//    if (afterDelay > 2000) delay(afterDelay.shake(300))
//    else if (afterDelay > 1000) delay(afterDelay.shake(200))
//    else if (afterDelay > 40) delay(afterDelay.shake(30))
//    else if (afterDelay > 0) delay(afterDelay)
//}
//// 上层一点
//suspend fun accClick(name: String, afterDelay: Long = 0) {
//    printLog { "accClick $name" }
//    if (name == btnMedicine) xLastUseMedicineTs = System.currentTimeMillis()
//    if (name == btnInteract) xLastInteractTs = System.currentTimeMillis()
//    if (name == btnInteract) releaseGActionByInteract++
//    if (releaseGActionByInteract > 0 && releaseGActionByInteract % 10 == 0 && Properties.scene != C.S_MYBL) {
//        releaseLastGestures() // 弹出了他人的信息菜单.需要重新摇杆消除弹窗
//        releaseGActionByInteract++
//    }
//    if (releaseGActionByInteract > 10000) releaseGActionByInteract = 1
//
//    innerPlayGestures(name = click, rockerAngle = null, btn = name)
//
//    if (afterDelay > 2000) delay(afterDelay.shake(300))
//    else if (afterDelay > 1000) delay(afterDelay.shake(200))
//    else if (afterDelay > 40) delay(afterDelay.shake(30))
//    else if (afterDelay > 0) delay(afterDelay)
//}
//
//suspend fun accPathfindingMapTarget(target: Block?, itemAction: suspend (index: Int, angle: Int)->Unit) {
//    if (target == null) return
//    if (bsPage != PAGE_MAIN) return
//    if (System.currentTimeMillis() - anaLastPageNotMainTs < 500) return // 避免卡摇杆
//    var offsetX = target.x - selfInSmallMap.x
//    var offsetY = target.y - selfInSmallMap.y
//    while (offsetX == 0 && offsetY == 0) {
//        offsetX = 0.shake(6)
//        offsetY = 0.shake(6)
//    }
//    val distance = sqrt((offsetX * offsetX + offsetY * offsetY).toDouble()).toInt()
//    val moveTime = min(3600L, max(splitTime, (distance / 1f.pt * 27).toLong())) // 1f.pt * 21
//    val moveStep: Int = max(1, (moveTime / splitTime).toInt())
//    val angle = App.take().pointToAngle(offsetX, offsetY)
//    printLog { "accPathfindingMapTarget [${target.name}] angle $angle moveStep $moveStep movingTime $moveTime distance $distance" }
//    repeat(moveStep) {
//        if (bsPage == PAGE_MAIN) {
//            itemAction.invoke(it, angle)
//        }
//    }
//    releaseLastGestures()
//}
//suspend fun accPathfinding(angle: Int?, btn: String? = null, disableSkillAlways: Boolean = false) {
//    if (angle == null) return
////    if (bsPage != PAGE_MAIN) return
//    if (System.currentTimeMillis() - anaLastPageNotMainTs < 500) return // 避免卡摇杆
//
//    if (anaCounterNoSkill > 330) {
//        releaseLastGestures() // 消除键盘.画面能看到人物血条.加半个屏幕的输入法.摇杆在字母上乱按
//        accClick(btnCenterTop, afterDelay = 400) // 消除键盘
//        accClick(btnCenterTop) // 消除键盘
//        anaCounterNoSkill = 0
//    }
//
//    val btn2: String? = if (btn.isNullOrEmpty() && medicine.usable && bsPlayerHp < 0.8f && System.currentTimeMillis() - xLastUseMedicineTs > 6000) {
//        btnMedicine
//    } else if (!disableSkillAlways && btn.isNullOrEmpty() && !bsSceneSettle && !bsSceneSettleBlacksmith) {
//        usableSkillAlways?.also { // 新增常驻寻路技能释放
////          这里打断的技能释放  releaseLastGestures()
//            it.useV2(angle)
//        }
//        btn
//    } else btn
//
//    if (btn2 == btnMedicine) xLastUseMedicineTs = System.currentTimeMillis()
//    if (btn2 == btnInteract) xLastInteractTs = System.currentTimeMillis()
//    if (btn2 == btnInteract) releaseGActionByInteract++
//    if (releaseGActionByInteract > 0 && releaseGActionByInteract % 10 == 0 && Properties.scene != C.S_MYBL) {
//        releaseLastGestures() // 弹出了他人的信息菜单.需要重新摇杆消除弹窗
//        releaseGActionByInteract++
//    }
//    if (releaseGActionByInteract > 10000) releaseGActionByInteract = 1
//
//    innerPlayGestures(name = pathfinding, rockerAngle = angle, rockerTime = splitTime.shake(10), btn = btn2)
//}
//
//suspend fun accAtkByKit(angleValue: Int?, btn: String) {
//    printLog { "accAtk btn $btn angle $angleValue" }
//
//    if (btn == btnMedicine) xLastUseMedicineTs = System.currentTimeMillis()
//    if (btn == btnInteract) xLastInteractTs = System.currentTimeMillis()
//    if (btn == btnInteract) releaseGActionByInteract++
//    if (releaseGActionByInteract > 0 && releaseGActionByInteract % 10 == 0 && Properties.scene != C.S_MYBL) {
//        releaseLastGestures() // 弹出了他人的信息菜单.需要重新摇杆消除弹窗
//        releaseGActionByInteract++
//    }
//    if (releaseGActionByInteract > 10000) releaseGActionByInteract = 1
//
//    val btnTime = takeBtnTapTime(btn)
//    val rockerTime = splitTime.shake(10) // if (System.currentTimeMillis() - anaLastHasEliteEnemyNameTs < 3000) 270L.shake(10) else max(btnTime, XGesturePoint.tapTime)
//    innerPlayGestures(name = atk, rockerAngle = angleValue, rockerTime = rockerTime, btn = btn, btnTime = btnTime)
//}
//
//data class XPoint(val x: Float, val y: Float)
//
//private val path1ByStrategy: Boolean get() {
//    return continueCounter++ > counterInterceptor
//}
//var continueCounter = 0
//private var lastRockerDown: XPoint? = null
//private var lastRockerMove: XPoint? = null
//private var lastBaseAtk: XPoint? = null
//
//
//data class GAction(
//    val name: String,
//    val rockerAngle: Int?,
//    val rockerTime: Long = tapTime,
//    val btn: String?,
//    val btnTime: Long = tapTime,
//    val end: Boolean = false,
//    val lastSd1: StrokeDescription?,
//    val lastSd2: StrokeDescription?,
//    val replacedCurrSd1: StrokeDescription? = null
//) {
//    private var path2EndX: Float? = null
//    private var path2EndY: Float? = null
//    private var path1Angle: Int? = null
//    private var path1EndX: Float? = null
//    private var path1EndY: Float? = null
//
//    fun takePath1End(): Path? {
//        val p1x = path1EndX ?: return null
//        val p1y = path1EndY ?: return null
//        val out = Path()
//        out.moveTo(p1x, p1y)
//        return out
//    }
//    fun takePath2End(): Path? {
//        val p2x = path2EndX ?: return null
//        val p2y = path2EndY ?: return null
//        val out = Path()
//        out.moveTo(p2x, p2y)
//        return out
//    }
//
//    private val path1: List<Path>? by lazy { // rocker
//        val prefabPath1Angle = path1Angle // 普攻中断后继续
//        val prefabPath1EndX = path1EndX
//        val prefabPath1EndY = path1EndY
//        if (prefabPath1Angle != null && prefabPath1EndX != null && prefabPath1EndY != null) {
//            val out = Path() // 这个逻辑返回不重要.主要是不会去干扰 'lastRockerMove' 导致卡死
//            out.moveTo(prefabPath1EndX, prefabPath1EndY)
//            listOf(out)
//        } else if (path1ByStrategy) {
//            counterInterceptor = 300.shake(150)
//            continueCounter = 0
//            path1Angle = null
//            path1EndX = null
//            path1EndY = null
//            lastRockerDown = null
//            lastRockerMove = null
//            null
//        } else {
//            val atvTs = System.currentTimeMillis() - xLastAtvTs
//            val sa = when  {
//                Properties.scene == C.S_MYBL -> if (System.currentTimeMillis() - anaLastMayHomeMapTs < 3000) 10
//                                                else 30
//                Properties.scene == C.S_DYWS -> 60 // 打野幅度大点
//                Properties.scene == C.S_FB -> 10 // 避免船内乱走
//                atvTs in 0..1000 -> 10  // 怪物打架的时段精准移动
//                atvTs in 1000..3000 -> 10
//                atvTs in 3000..8000 -> 10
//                atvTs in 8000..16000 -> 10
//                atvTs in 16000..24000 -> 15
//                atvTs in 24000..30000 -> 40
//                else -> 50
//            }
//            val angle = rockerAngle?.shake(sa) ?: return@lazy null
//            path1Angle = angle
//            val rockerDown = lastRockerDown ?: rockerDownRandomPoint
//            val rockerMove = lastRockerMove ?: rockerDown
//            if (lastRockerDown == null) lastRockerDown = rockerDown
//            val startX = rockerMove.x
//            val startY = rockerMove.y
//            // 这里差不多有230的空间.因为向上调整了60.开始只有170的空间
//            val endXY = App.take().angleToPoint(rockerDown.x, rockerDown.y, angle, takeRockerLength(angle))
//            val endX = endXY.first
//            val endY = endXY.second
//            path1EndX = endX
//            path1EndY = endY
//            lastRockerMove = XPoint(endX, endY)
//            createHumanLikePathList(startX, startY, endX, endY)
//        }
//    }
//    private val path2: Path? by lazy {
//        val btnBlock = takeBtn(btn) ?: return@lazy null
//        val baseAtk = lastBaseAtk
//        if (btn == btnAtk && baseAtk != null) {
//            // 继续返回上次的
//            path2EndX = baseAtk.x
//            path2EndY = baseAtk.y
//            val out = Path()
//            out.moveTo(baseAtk.x, baseAtk.y)
//            out
//        } else {
//            val endXY = btnBlock.x.shake((btnBlock.width * 0.42f).toInt()) to btnBlock.y.shake((btnBlock.height * 0.42f).toInt())
//            val endX: Float = max(clickAreaEdge, min(phoneScreenWidth - clickAreaEdge, endXY.first.randomFloat))
//            val endY: Float = max(clickAreaEdge, min(phoneScreenHeight - clickAreaEdge, endXY.second.randomFloat))
//            if (btn == btnAtk) {
//                lastBaseAtk = XPoint(endX, endY)
//                path2EndX = endX
//                path2EndY = endY
//            }
//            val out = Path()
//            out.moveTo(endX, endY)
//            out
//        }
//    }
//
//    private val sd1: List<StrokeDescription> by lazy {
//        if (replacedCurrSd1 != null) {
//            // 替换了上次的摇杆. 直接返回
//            return@lazy listOf(replacedCurrSd1)
//        }
//
//        val out = mutableListOf<StrokeDescription>()
//        val linkLast = lastSd1?.willContinue() == true
//        var tempLast: StrokeDescription? = null
//        path1?.forEachIndexed { index, p1 ->
//            val ls1 = lastSd1
//            val s = if (ls1 != null && linkLast && index == 0) {
//                // 最后一个path. 继续上次的
//                ls1.continueStroke(p1, 0, sTime, true)
//            } else {
//                tempLast?.continueStroke(p1, 0, sTime, true)
//                    ?: StrokeDescription(p1, 0, sTime, true)
//            }
//            out.add(s)
//            tempLast = s
//        }
//        out
//    }
////
//    private val sd2: List<StrokeDescription> by lazy {
//        val out = mutableListOf<StrokeDescription>()
//        val linkLast = lastSd2?.willContinue() == true
//
////        val nextBaseWillContinue = false
//        var tempLast: StrokeDescription? = null
//        path2?.also { p2 ->
//            val p1Size = path1?.size ?: 0
//            val nextBaseWillContinue = btn == btnAtk && p1Size > 0  // && atkContinueByStrategy
//
//            val c = if (p1Size == 0) (btnTime / sTime).toInt()
//            else max(1, if (nextBaseWillContinue) p1Size else min(p1Size - 10, (btnTime / sTime).toInt()))
//
////            val originC = (btnTime / sTime).toInt()
////            val min = min(p1Size - 1, originC)
////            val max = max(p1Size - 1, originC)
////            val fixedC = if (btn == btnAtk) (min .. max).random() else originC
////            val c = max(1, min(p1Size - 1, fixedC))
////            val c = max(1, if (nextBaseWillContinue) p1Size else min(p1Size - 1, (btnTime / sTime).toInt()))
////            val c = max(1, min(p1Size - 1, (btnTime / sTime).toInt()))
//
//            repeat(c) { index ->
//                val ls2 = lastSd2
//                val nwc = (index < c - 1) || nextBaseWillContinue
//                val s = if (ls2 != null && linkLast && index == 0) {
//                    // 最后一个path. 继续上次的
//                    ls2.continueStroke(p2, 0, sTime, nwc) // 非普攻会自己收掉结尾
//                } else {
//                    tempLast?.continueStroke(p2, 0, sTime, nwc) // 非普攻会自己收掉结尾
//                        ?: StrokeDescription(p2, 1, sTime, nwc) // 非普攻会自己收掉结尾
//                }
//                out.add(s)
//                tempLast = s
//            }
//        }
//        out
//    }
//
//    val strokeDescriptions by lazy {
//        val out = mutableListOf<Pair<StrokeDescription?, StrokeDescription?>>()
//        repeat(max(sd1.size, sd2.size)) { index ->
//            out.add(sd1.getOrNull(index) to sd2.getOrNull(index))
//        }
//        out
//    }
//
//    override fun toString(): String {
//        val out = StringBuilder()
//        if (path1Angle != null) out.append("[摇杆(a:$path1Angle)时长:${rockerTime}]")
//        if (btn?.isNotEmpty() == true) {
//            out.append("[${btn}(时长:${btnTime};${takeBtn(btn)?.x},${takeBtn(btn)?.y})]")
//        }
//        return out.toString()
//    }
//
//    fun replaceExcludeBtn(invokedSd1: StrokeDescription?): GAction {
//        return GAction(name, rockerAngle, rockerTime, null, btnTime, end, null, null,
//            replacedCurrSd1 = invokedSd1).also {
//            it.path1Angle = path1Angle
//            it.path1EndX = path1EndX
//            it.path1EndY = path1EndY
//        }
//    }
//}
//
//private var lastAction: GAction? = null
//
//private suspend fun innerPlayGestures(
//    name: String,
//    rockerAngle: Int?,
//    rockerTime: Long = tapTime,
//    btn: String?,
//    btnTime: Long = tapTime,
//    end: Boolean = false,
//    traceless: Boolean = false,
//) = withContext(Dispatchers.Main) {
//    // GAction 构建务必在Main. GAction构建内的逻辑在Main线程. 和释放对应
//    val service = takeService() ?: return@withContext
//    delay(sTime) // 这里和之前的手势错开
//    // Android8.0
//    if (lastAction?.rockerAngle != null && rockerAngle == null) {
//        releaseLastGestures(END_ALL) // 摇杆结束
//    }
//    else if (lastAction?.btn == btnAtk && btn != btnAtk) {
//        releaseLastGestures(END_PATH_2) // 普攻结束
//    }
//    check()
//    val lastActionSdList = lastAction?.strokeDescriptions
//    val action = GAction(name, rockerAngle, rockerTime, btn, btnTime, end,
//        lastActionSdList?.lastOrNull()?.first, lastActionSdList?.lastOrNull()?.second)
//
//    val sdList = action.strokeDescriptions
//    if (sdList.isEmpty()) {
//        printLogE { "access playGestures ${action.name} sdList empty" }
//        releaseLastGestures( END_ALL) //比如这里有个超次数打断.
//        return@withContext
//    }
//    sdList.forEach { item ->
//        val builder = GestureDescription.Builder()
//        item.first?.also { builder.addStroke(it) }
//        item.second?.also { builder.addStroke(it) }
//        val description = builder.build()
//        service.dispatchGesture(description, null, null)
//        delay(sTime)
//    }
//    printLog { "access invoked $action" }
//    lastAction = action
//
//    // 记录最后一次点击的时间戳
//    if (!traceless) lastAccInvokedTs = System.currentTimeMillis()
//}
//
//const val END_ALL = 0
//private const val END_PATH_2 = 2 // 只释放攻击按钮. 和 技能A|技能B|技能C|技能D|技能E|技能F|互动|血条
//suspend fun releaseLastGestures(
//    type: Int = END_ALL
//) = withContext(Dispatchers.Main) {
//    val service = takeService() ?: return@withContext
//    val action = lastAction ?: return@withContext
//    printLog { "access releaseLastGestures $action $type" }
//    val sTime = 3L
//    val builder = GestureDescription.Builder()
//    var replacedCurrSd1: StrokeDescription? = null
//    var emptyStroke = true
//        // 这里面有空没走的情况
//    action.strokeDescriptions.lastOrNull()?.first?.also {
//        if (type == END_PATH_2) {
//            val sd = it.continueStroke(action.takePath1End(), 0, sTime, true)
//            builder.addStroke(sd)
//            emptyStroke = false
//            replacedCurrSd1 = sd
//        } else {
//            val sd = it.continueStroke(action.takePath1End(), 0, sTime, false)
//            builder.addStroke(sd)
//            emptyStroke = false
//        }
//    }
//    action.strokeDescriptions.lastOrNull()?.second?.also {
//        if (it.willContinue()) {
//            builder.addStroke(it.continueStroke(action.takePath2End(), 0, sTime, false))
//            emptyStroke = false
//        }
//    }
//    if (emptyStroke) {
//        printLogE { "access releaseLastGestures empty stroke" }
//        lastAction = null // release in main thread
//        lastRockerDown = null
//        lastRockerMove = null
//        lastBaseAtk = null
//        return@withContext // Cause by java.lang.IllegalStateException Gestures must have at least one stroke
//    }
//
//    service.dispatchGesture(builder.build(), null, null)
//    if (type == END_ALL) {
//        lastAction = null // release in main thread
//        lastRockerDown = null
//        lastRockerMove = null
//        lastBaseAtk = null
//    } else if (type == END_PATH_2) {
//        lastAction = action.replaceExcludeBtn(invokedSd1 = replacedCurrSd1)
//        printLog { "release path1 replace [${lastAction}] sd1 $replacedCurrSd1" }
//        lastBaseAtk = null
//    }
//    delay(sTime)
//
//}
//
//private suspend fun takeService(): CloudBackupService? {
//    if (Accessibility.itc) {
//        delay(1000)
//        printLogE { "access intercepted" }
//        return null
//    }
//    val service = CloudBackupService.ins
//    if (service == null) {
//        printLogE { "access service null" }
//        return null
//    }
//    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
//        printLogE { "access system too old" }
//        return null
//    }
//    return service
//}
//
//private var checkTs = 0L
//private fun check() {
//    if (System.currentTimeMillis() - checkTs > 598000) {
//        if (Controller.isRunning) {
//            if (Keys.isUsingCDKeyInfoActivating != 0) {
//                // 卡密已失效[$a]
//                Controller.isInvalid.postValue(true)
//                DiskLogUtils.saveToDisk()
//            }
//            checkTs = System.currentTimeMillis()
//        }
//    }
//}
//private val decelerateInterpolator = DecelerateInterpolator(0.85f)
//private val accelerateInterpolator = AccelerateInterpolator(1.15f)
//private val accelerateDecelerateInterpolator = AccelerateDecelerateInterpolator()
//private val overshootInterpolator = OvershootInterpolator(0.85f)
//
//
//private fun createHumanLikePathList(
//    startX: Float, startY: Float,
//    endX: Float, endY: Float,
//): List<Path> {
//    val interpolator = when(random.nextInt(4)) {
//        0 -> accelerateInterpolator
//        1 -> decelerateInterpolator
//        2 -> accelerateDecelerateInterpolator
//        else -> overshootInterpolator
//    }
//    // 1. 创建两个中间控制点（带随机偏移）
//    val a = (3 .. 47).random() / 100f
//    val b = (53 .. 97).random() / 100f
//    val (mid1X, mid1Y) = createRandomMidPoint(startX, startY, endX, endY, a)
//    val (mid2X, mid2Y) = createRandomMidPoint(startX, startY, endX, endY, b)
//
//    // 2. 在贝塞尔曲线上采样点
//    // 4ms一次 63.75点是255毫秒
//    // 255 除3.5 = 72 用72波动. 走路走少了感觉
//    val pointCount = (68 .. 76).random()
//    val points = mutableListOf<Pair<Float, Float>>()
//
//    for (i in 0..pointCount) {
//        // 计算线性进度 (0.0 - 1.0)
//        val linearProgress = i.toFloat() / pointCount
//        // 应用插值器获取非线性进度
//        val acceleratedProgress = interpolator.getInterpolation(linearProgress)
//
//        // 计算贝塞尔曲线上的点
//        val curvePoint = calculateBezierPoint(
//            startX, startY,
//            mid1X, mid1Y,
//            mid2X, mid2Y,
//            endX, endY,
//            acceleratedProgress
//        )
//
//        // 添加速度相关的抖动（中间大，两端小）
//        //val maxJitter = 0//(6.pt * sin(acceleratedProgress * PI).toFloat() * 0.8f + 1.5f).toInt()
//        val jitterX = 0 //(-maxJitter..maxJitter).random().toFloat()
//        val jitterY = 0 //(-maxJitter..maxJitter).random().toFloat()
//
//        // 应用抖动并确保在屏幕边界内
//        val finalX = (curvePoint.first + jitterX).coerceIn(clickAreaEdge, phoneScreenWidth - clickAreaEdge)
//        val finalY = (curvePoint.second + jitterY).coerceIn(clickAreaEdge, phoneScreenHeight - clickAreaEdge)
//
//        points.add(finalX to finalY)
//    }
//
//    // 3. 创建路径段列表
//    val pathList = mutableListOf<Path>()
//    var lastX = startX
//    var lastY = startY
//
//    for (point in points) {
//        val (currX, currY) = point
//
//        // 创建新路径段
//        val segmentPath = Path()
//        segmentPath.moveTo(lastX, lastY)
//
//        // 使用直线连接（因为点足够密集）
//        segmentPath.lineTo(currX, currY)
//
//        pathList.add(segmentPath)
//
//        // 更新最后位置
//        lastX = currX
//        lastY = currY
//    }
//
//    // 添加最后一段到终点
//    val finalPath = Path()
//    finalPath.moveTo(lastX, lastY)
//    finalPath.lineTo(endX, endY)
//    pathList.add(finalPath)
//
//    return pathList
//}
//
//private val takeRandomOffset: Float get() {
//    return when (random.nextInt(3)) {
//        0 -> 0.35f
//        else -> 0.65f
//    }
//}
//
//// 创建随机中间点（带偏移）
//private fun createRandomMidPoint(
//    startX: Float, startY: Float,
//    endX: Float, endY: Float,
//    fraction: Float,
//): Pair<Float, Float> {
//    // 计算基础位置
//    val baseX = startX + (endX - startX) * fraction
//    val baseY = startY + (endY - startY) * fraction
//
//    // 计算最大偏移量（基于路径长度的15%）
//    val pathLength = hypot(endX - startX, endY - startY)
//    val maxOffset = (pathLength * takeRandomOffset).toInt()
//
//    // 添加随机偏移
//    val offsetX = (-maxOffset..maxOffset).random()
//    val offsetY = (-maxOffset..maxOffset).random()
//
//    // 确保在屏幕边界内
//    val finalX = (baseX + offsetX).coerceIn(clickAreaEdge, phoneScreenWidth - clickAreaEdge)
//    val finalY = (baseY + offsetY).coerceIn(clickAreaEdge, phoneScreenHeight - clickAreaEdge)
//
//    return finalX to finalY
//}
//
//// 计算三次贝塞尔曲线上的点
//private fun calculateBezierPoint(
//    startX: Float, startY: Float,
//    ctrl1X: Float, ctrl1Y: Float,
//    ctrl2X: Float, ctrl2Y: Float,
//    endX: Float, endY: Float,
//    t: Float
//): Pair<Float, Float> {
//    val u = 1 - t
//    val tt = t * t
//    val uu = u * u
//    val uuu = uu * u
//    val ttt = tt * t
//
//    // 三次贝塞尔曲线公式
//    val x = uuu * startX +
//            3 * uu * t * ctrl1X +
//            3 * u * tt * ctrl2X +
//            ttt * endX
//
//    val y = uuu * startY +
//            3 * uu * t * ctrl1Y +
//            3 * u * tt * ctrl2Y +
//            ttt * endY
//
//    return x to y
//}